#include "FaceRecognition.h"
#include "ui_FaceRecognition.h"
#include <QBitmap>
#include <QPainter>
#include <QStyleOption>
#include <QImage>
#include <QPixmap>
#include <QDebug>
#include <QMessageBox>
#include <QTcpSocket>

QPixmap PixmapToRound(const QPixmap &src, int radius);

FaceRecognition::FaceRecognition(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::FaceRecognition)
    , timer(new QTimer(this))
    , timer1(new QTimer(this))
    , sameLabelCount(0)
{
    ui->setupUi(this);

    connect(ui->face, &QPushButton::clicked, this, &FaceRecognition::faceclicked);

    connect(timer, &QTimer::timeout, this, &FaceRecognition::updateDateTime);
    timer->start(1000);
    updateDateTime();

    // 隐藏原生标题栏
    setWindowFlags(Qt::FramelessWindowHint | Qt::Dialog);

    // 防止窗口背景透明
    setAttribute(Qt::WA_TranslucentBackground, false);

    // 点击关闭按钮关闭窗口
    connect(ui->closeButton, &QPushButton::clicked, this, &FaceRecognition::close);

    // 加载分类器
    if (!cascade.load("D:\\Qt_project\\FaceRecognition\\haarcascade_frontalface_alt2.xml"))
    {
        qDebug() << "Error loading cascade file.";
        return;
    }

    // 加载模型
    model = cv::face::FisherFaceRecognizer::create();
    model->read("MyFaceFisherModel.xml");

    // 初始化UI组件
    ui->label_2->setScaledContents(true);
}

FaceRecognition::~FaceRecognition()
{
    cap.release();
    delete ui;
}

// 实现窗口拖动功能
void FaceRecognition::mousePressEvent(QMouseEvent *event)
{
    // 检查是否点击了自定义标题栏
    if (event->button() == Qt::LeftButton && event->pos().y() <= 81) {
        m_isTitleBarClicked = true;
        m_dragPosition = event->globalPos() - frameGeometry().topLeft();
        event->accept();
    } else {
        m_isTitleBarClicked = false;
        // 让事件继续传播，确保其他控件能响应点击事件
        QWidget::mousePressEvent(event);
    }
}

void FaceRecognition::mouseMoveEvent(QMouseEvent *event)
{
    // 只有在点击了标题栏之后才允许拖动
    if (m_isTitleBarClicked && (event->buttons() & Qt::LeftButton)) {
        move(event->globalPos() - m_dragPosition);
        event->accept();
    } else {
        // 让事件继续传播，确保其他控件能响应移动事件
        QWidget::mouseMoveEvent(event);
    }
}

void FaceRecognition::paintEvent(QPaintEvent *event)
{
    // 1. 绘制样式（QSS）
    QStyleOption opt;
    opt.initFrom(this);
    QPainter p(this);
    style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); // 绘制样式

    // 2. 设置掩码，约定 painter 绘制区域
    QBitmap bmp(this->size());
    bmp.fill(Qt::white); // 填充 bitmap

    QPainter painter(&bmp);
    painter.setPen(Qt::NoPen);
    painter.setBrush(Qt::black); // 掩码值
    painter.drawRoundedRect(bmp.rect(), 30, 30); // 在 bitmap 中绘制圆角矩形

    // 设置掩码以确定本控件可绘制区域
    setMask(bmp);

    // 调用基类的 paintEvent
    QWidget::paintEvent(event);
}

void FaceRecognition::updateDateTime()
{
    QDateTime currentDateTime = QDateTime::currentDateTime();

    QString timeString = currentDateTime.toString("HH:mm:ss");
    ui->time->setText(timeString);

    QString dateString = currentDateTime.toString("M月d日 dddd");
    ui->date->setText(dateString);
}

void FaceRecognition::faceclicked()
{
    // 按钮点击时启动摄像头
    if (!cap.isOpened())
    {
        cap.open(0);
        if (!cap.isOpened())
        {
            qDebug() << "Error opening video capture.";
            return;
        }

        // 连接定时器的超时信号到更新帧的槽函数
        connect(timer1, &QTimer::timeout, this, &FaceRecognition::updateFrame);
        timer1->start(100); // 每100毫秒更新一次帧
    }
}

void FaceRecognition::convertMatToQImage(const cv::Mat& mat, QImage& image)
{
    // 将 OpenCV 的 Mat 转换为 QImage
    switch (mat.type())
    {
    case CV_8UC1:
        image = QImage(mat.data, mat.cols, mat.rows, mat.step, QImage::Format_Grayscale8);
        break;
    case CV_8UC3:
        image = QImage(mat.data, mat.cols, mat.rows, mat.step, QImage::Format_RGB888).rgbSwapped();
        break;
    default:
        qDebug() << "Unsupported Mat format.";
        break;
    }
}

int FaceRecognition::Predict(const cv::Mat& src_image)
{
    cv::Mat face_test;
    int predict = 0;
    if (src_image.rows >= 120)
    {
        cv::resize(src_image, face_test, cv::Size(92, 112));
    }
    if (!face_test.empty())
    {
        predict = model->predict(face_test);
    }
    return predict;
}

void FaceRecognition::updateFrame()
{
    cv::Mat frame;
    cap >> frame;
    if (frame.empty())
        return;

    cv::Mat gray;
    cv::cvtColor(frame, gray, cv::COLOR_BGR2GRAY);
    cv::equalizeHist(gray, gray);

    std::vector<cv::Rect> faces;
    cascade.detectMultiScale(gray, faces, 1.1, 4, 0 | cv::CASCADE_DO_ROUGH_SEARCH, cv::Size(30, 30), cv::Size(500, 500));

    for (const auto& face : faces)
    {
        cv::Mat faceROI = gray(face);
        int label = Predict(faceROI);
        qDebug() << label;

        // 将 label 直接转换为 QString
        QString currentLabel = QString::number(label);

        // 只有在标签不为"Error"时才进行处理
        if (currentLabel != "Error") {
            if (currentLabel == lastLabel) {
                sameLabelCount++;  // 标签相同，计数+1
            } else {
                lastLabel = currentLabel;
                sameLabelCount = 1;  // 不同标签，重置计数器
            }

            // 如果连续5次检测到相同标签
            if (sameLabelCount >= 5) {
                // 停止摄像头和定时器，关闭检测
                cap.release();
                timer1->stop();
                disconnect(timer1, &QTimer::timeout, this, &FaceRecognition::updateFrame);

                sameLabelCount = 0;

                // 通过TCP将标签发送到服务器
                QTcpSocket *socket = new QTcpSocket(this);
                socket->connectToHost("127.0.0.1", 12355); // 替换为实际的服务器IP和端口

                connect(socket, &QTcpSocket::connected, [this, socket, currentLabel]() {
                    QString message = QString("%1").arg(currentLabel);
                    socket->write(message.toUtf8());
                });


                // 处理服务器的响应
                connect(socket, &QTcpSocket::readyRead, [this, socket]() {
                    QByteArray response = socket->readAll();
                    QString responseStr = QString::fromUtf8(response);  // 去除多余的空格或换行符

                    // 按照换行符分割多个消息
                    QStringList messages = responseStr.split('\n', Qt::SkipEmptyParts);

                    // 依次处理每个消息
                    for (const QString &result : messages) {
                        qDebug() << "服务器响应：" << result;

                        // 处理不同的服务器响应
                        if (result.startsWith("NOT_FOUND")) {
                            // QMessageBox::warning(this, "提示", "未成功识别");
                            MyMessageBox msgBox;
                            msgBox.setWindowTitle("提示");
                            msgBox.setText("未成功识别");
                            msgBox.setButton("确定");
                            msgBox.exec();
                        } else if (result.startsWith("NO_ATTENDANCE")) {
                            QStringList parts = result.split("-");
                            if (parts.size() == 2) {
                                // QMessageBox::warning(this, "提示", "未有考勤任务（" + parts[1] + "）");
                                MyMessageBox msgBox;
                                msgBox.setWindowTitle("提示");
                                msgBox.setText("未有考勤任务（" + parts[1] + "）");
                                msgBox.setButton("确定");
                                msgBox.exec();
                            } else {
                                // QMessageBox::warning(this, "提示", "未有考勤任务");
                                MyMessageBox msgBox;
                                msgBox.setWindowTitle("提示");
                                msgBox.setText("未有考勤任务");
                                msgBox.setButton("确定");
                                msgBox.exec();
                            }
                        } else if (result.startsWith("NOT_IN_TIME")) {
                            QStringList parts = result.split("-");
                            if (parts.size() == 2) {
                                // QMessageBox::warning(this, "提示", "未在考勤时间段内（" + parts[1] + "）");
                                MyMessageBox msgBox;
                                msgBox.setWindowTitle("提示");
                                msgBox.setText("未在考勤时间段内（" + parts[1] + "）");
                                msgBox.setButton("确定");
                                msgBox.exec();
                            } else {
                                // QMessageBox::warning(this, "提示", "未在考勤时间段内");
                                MyMessageBox msgBox;
                                msgBox.setWindowTitle("提示");
                                msgBox.setText("未在考勤时间段内");
                                msgBox.setButton("确定");
                                msgBox.exec();
                            }
                        } else if (result.startsWith("SUCCESS")) {
                            QStringList parts = result.split("-");
                            if (parts.size() == 3) {
                                // QMessageBox::information(this, "提示", parts[1] + "（" + parts[2] + "），已成功打卡");
                                MyMessageBox msgBox;
                                msgBox.setWindowTitle("提示");
                                msgBox.setText(parts[1] + "（" + parts[2] + "），已成功打卡");
                                msgBox.setButton("确定");
                                msgBox.exec();
                            }
                        } else if (result.startsWith("DUPLICATE_ATTENDANCE")) {
                            QStringList parts = result.split("-");
                            if (parts.size() == 2) {
                                // QMessageBox::warning(this, "提示", "重复打卡（" + parts[1] + "）");
                                MyMessageBox msgBox;
                                msgBox.setWindowTitle("提示");
                                msgBox.setText("重复打卡（" + parts[1] + "）");
                                msgBox.setButton("确定");
                                msgBox.exec();
                            }
                        } else {
                            // QMessageBox::warning(this, "提示", "未知响应：" + result);
                            MyMessageBox msgBox;
                            msgBox.setWindowTitle("提示");
                            msgBox.setText("未知响应：" + result);
                            msgBox.setButton("确定");
                            msgBox.exec();
                        }
                    }

                    socket->deleteLater();  // 确保在完成后释放 socket
                });

                return;
            }
        }

        cv::rectangle(frame, face, cv::Scalar(0, 255, 0), 2);
        cv::putText(frame, currentLabel.toStdString(), face.tl(), cv::FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(0, 0, 255), 2);
    }

    QImage image = QImage(frame.data, frame.cols, frame.rows, frame.step, QImage::Format_BGR888);
    QPixmap pixmap = QPixmap::fromImage(image);

    int radius = std::min(ui->label_2->width(), ui->label_2->height()) / 2;
    QPixmap roundedPixmap = PixmapToRound(pixmap, radius);

    ui->label_2->setPixmap(roundedPixmap.scaled(ui->label_2->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation));
}

QPixmap PixmapToRound(const QPixmap &src, int radius)
{
    if (src.isNull()) {
        return QPixmap();
    }
    QSize size(2*radius, 2*radius);
    QBitmap mask(size);
    QPainter painter(&mask);
    painter.setRenderHint(QPainter::Antialiasing);
    painter.setRenderHint(QPainter::SmoothPixmapTransform);
    painter.fillRect(0, 0, size.width(), size.height(), Qt::white);
    painter.setBrush(QColor(0, 0, 0));
    painter.drawRoundedRect(0, 0, size.width(), size.height(), 250, 250);
    QPixmap image = src.scaled(size);
    image.setMask(mask);
    return image;

}
